#ifndef NANE_MANAGER_H
#   define  NANE_MANAGER_H

#   include <algorithm>
#   include <functional>
#   include <vector>
#   include <utility>

namespace nane 
{
    template<typename TKey>
    struct DefaultComparator
    {
        const TKey& key;
        DefaultComparator( const TKey& _key )
            : key( _key )
        {
        }
        
        bool operator()( const TKey& _testKey )
        {
            return key == _testKey;
        }
    };
    
    template<typename TKey, class TSubSystem, class TComparator = DefaultComparator<TKey> >
    class Manager
    {
    public:
        static bool AddInterface( const TKey& _key, TSubSystem* _subSystem )
        {
            typename TSubSystemMap::iterator it_find = 
                    std::find_if(subSystemMap().begin(), subSystemMap().end(), FindByKey<DefaultComparator<TKey> >(_key) );
            if( it_find != subSystemMap().end() )
            {
                return false;
            }
            subSystemMap().push_back(std::make_pair(_key, _subSystem));
            return true;
        }
        
        static void RemoveInterface( const TKey& _key )
        {
            typename TSubSystemMap::iterator it_end = 
                    std::remove_if(subSystemMap().begin(), subSystemMap().end(), FindByKey<DefaultComparator<TKey> >(_key));
            subSystemMap().erase(it_end, subSystemMap().end());
        }
        
        static void RemoveInterface( TSubSystem* _subSystem )
        {
            typename TSubSystemMap::iterator it_end = 
                    std::remove_if(subSystemMap().begin(), subSystemMap().end(), FindBySubSystem(_subSystem));
            subSystemMap().erase(it_end, subSystemMap().end());
        }
        
        static void AddAlias( const TKey& _alias, const TKey& _key )
        {
            typename TAliasesMap::iterator it_find =
                    std::find_if(aliasesMap().begin(), aliasesMap().end(), FindAliasByAlias<DefaultComparator<TKey> >(_alias));
            if( it_find != aliasesMap().end() )
            {
                it_find->second = _alias;
            }
            else
            {
                aliasesMap().push_back(std::make_pair(_alias, _key));
            }
        }
        
        static void RemoveAlias( const TKey& _alias )
        {
            typename TAliasesMap::iterator it_end = 
                    std::remove_if(aliasesMap().begin(), aliasesMap().end(), FindAliasByAlias<DefaultComparator<TKey> >(_alias));
            aliasesMap().erase(it_end);
        }
        
        static void RemoveAll()
        {
            subSystemMap().clear();
            aliasesMap().clear();
        }
        
        static void DestroyAll()
        {
            for( typename TSubSystemMap::iterator it = subSystemMap().begin(), it_end = subSystemMap().end();
                it != it_end;
                ++it )
            {
                delete it->second;
            }
            RemoveAll();
        }
        
        static TSubSystem* Instance( const TKey& _key )
        {
            TSubSystem* subSystemInstance = FindSubSystem_(_key);
            if( subSystemInstance == NULL )
            {
                // try find alias
                typename TAliasesMap::iterator it_find = 
                    std::find_if(aliasesMap().begin(), aliasesMap().end(), FindAliasByAlias<TComparator>(_key));
                if( it_find != aliasesMap().end() )
                {
                    subSystemInstance = FindSubSystem_(it_find->second);
                }
            }
            return subSystemInstance;
        }
        
    private:
        
        template<class TCompare>
        struct FindByKey
        {
            TCompare compare;
            FindByKey( const TKey& _key )
                : compare(_key)
            {
            }
            
            bool operator()( const std::pair<TKey, TSubSystem*>& _value )
            {
                return compare(_value.first);
            }
        };
        
        struct FindBySubSystem
        {
            TSubSystem* subSystem;
            FindBySubSystem( TSubSystem* _subSystem )
                : subSystem( _subSystem )
            {
                
            }
            
            bool operator()( const std::pair<TKey, TSubSystem*>& _value )
            {
                return subSystem == _value.second;
            }
        };
        
        template<class TCompare>
        struct FindAliasByAlias
        {
            TCompare compare;
            FindAliasByAlias( const TKey& _alias )
                : compare( _alias )
            {
            }
            
            bool operator()( const std::pair<TKey, TKey>& _value )
            {
                return compare(_value.first);
            }
        };
        
    private:
        static TSubSystem* FindSubSystem_( const TKey& _key )
        {
            TSubSystem* subSystemInstance = NULL;
            typename TSubSystemMap::iterator it_find = 
                    std::find_if(subSystemMap().begin(), subSystemMap().end(), FindByKey<TComparator>(_key));
            if( it_find != subSystemMap().end() )
            {
                subSystemInstance = it_find->second;
            }
            return subSystemInstance;
        }
        
    private:
        typedef std::vector< std::pair<TKey, TSubSystem*> > TSubSystemMap;
        static TSubSystemMap& subSystemMap()
        {
            static TSubSystemMap s_subSystemMap;
            return s_subSystemMap;
        }
        
        typedef std::vector< std::pair<TKey, TKey> > TAliasesMap;
        static TAliasesMap& aliasesMap()
        {
            static TAliasesMap s_aliasesMap;
            return s_aliasesMap;
        }
    };
    
    
}   // namespace nane

#endif	// NANE_MANAGER_H
